package com.yuncommunity.runcircle;

import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.BitmapFactory;
import android.location.GpsSatellite;
import android.location.GpsStatus;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.v7.app.AlertDialog;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.location.LocationManagerProxy;
import com.amap.api.location.LocationProviderProxy;
import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdate;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.LocationSource;
import com.amap.api.maps.MapView;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.Polyline;
import com.amap.api.maps.model.PolylineOptions;
import com.oldfeel.utils.DensityUtil;
import com.oldfeel.utils.NetUtil;
import com.oldfeel.utils.StringUtil;
import com.pgyersdk.update.PgyUpdateManager;
import com.yuncommunity.runcircle.base.MyActivity;
import com.yuncommunity.runcircle.conf.JsonApi;
import com.yuncommunity.runcircle.conf.Net;
import com.yuncommunity.runcircle.conf.UserInfo;
import com.yuncommunity.runcircle.db.DBHelper;
import com.yuncommunity.runcircle.item.LocationItem;
import com.yuncommunity.runcircle.service.LocationService;
import com.yuncommunity.runcircle.util.MyUtil;

import org.json.JSONException;
import org.json.JSONObject;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class MainActivity extends MyActivity implements AMapLocationListener, LocationSource {
    private static final int MESSAGE_UPDATE_TIME = 1;

    @Bind(R.id.ic_gps)
    ImageView icGps;
    @Bind(R.id.all_times)
    TextView allTimes;
    @Bind(R.id.all_distance)
    TextView allDistance;
    @Bind(R.id.map)
    MapView mapView;
    @Bind(R.id.start)
    ImageButton start;
    @Bind(R.id.detail)
    ImageButton detail;
    @Bind(R.id.all_info)
    LinearLayout allInfo;
    @Bind(R.id.time)
    TextView tvTime;
    @Bind(R.id.speed)
    TextView tvSpeed;
    @Bind(R.id.distance)
    TextView tvDistance;
    @Bind(R.id.calories)
    TextView tvCalories;
    @Bind(R.id.run_info)
    LinearLayout runInfo;
    @Bind(R.id.find_gps_info_1)
    public LinearLayout findGpsInfo1;
    @Bind(R.id.find_gps_info_2)
    public LinearLayout findGpsInfo2;
    @Bind(R.id.find_gps)
    public LinearLayout findGps;
    @Bind(R.id.main_root)
    LinearLayout mainRoot;
    @Bind(R.id.goon)
    Button goon;
    @Bind(R.id.complete)
    Button complete;
    @Bind(R.id.push_control)
    LinearLayout pushControl;
    private AMap aMap;
    private OnLocationChangedListener myLocationListener;
    private LocationManagerProxy mAMapLocationManager;
    private DBHelper dbHelper;
    private double distance;
    private UserInfo userInfo;
    private LocationService locationService;
    private float dX, dY; // 触摸点与 start 按钮的坐标差
    private float startX, startY; // start 按钮的坐标
    private int maxBottom;
    private List<LocationItem> locationList = new ArrayList<>();
    private Polyline polyline;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        mapView.onCreate(savedInstanceState);
        initMap();
        userInfo = UserInfo.getInstance();
        dbHelper = DBHelper.getInstance(this);
        bindService(new Intent(this, LocationService.class), serviceConnect, BIND_AUTO_CREATE);
        maxBottom = DensityUtil.dip2px(this, 48);

        PgyUpdateManager.register(this);

        start.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent event) {
                if (locationService.getState() != LocationService.STATE_RUNNING) {
                    return false;
                }
                switch (event.getActionMasked()) {
                    case MotionEvent.ACTION_DOWN:
                        startX = view.getX();
                        startY = view.getY();
                        dX = view.getX() - event.getRawX();
                        dY = view.getY() - event.getRawY();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        if (event.getRawY() > mainRoot.getBottom() - maxBottom) {
                            start.setVisibility(View.GONE);
                            pushControl.setVisibility(View.VISIBLE);
                            locationService.setState(LocationService.STATE_PUSH);
                            return false;
                        }
                        view.animate()
                                .x(event.getRawX() + dX)
                                .y(event.getRawY() + dY)
                                .setDuration(0)
                                .start();
                        break;
                    case MotionEvent.ACTION_UP:
                        view.animate().x(startX).y(startY).setDuration(0).start();
                        break;
                    default:
                        return false;
                }
                return true;
            }
        });

        getAllData();
    }

    private void getAllData() {
        Net net = new Net(this, JsonApi.getTotalSportData);
        net.sendPost(new NetUtil.OnJsonResultListener() {
            @Override
            public void onSuccess(String data) {
                try {
                    JSONObject json = new JSONObject(data);
                    allDistance.setText(json.getJSONObject("distance").getString("value"));
                    allTimes.setText(json.getJSONObject("times").getString("value"));
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onFail(int code, String data) {
                showToast("getTotalSportData 失败");
            }
        });
    }

    private ServiceConnection serviceConnect = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            locationService = ((LocationService.LocalBinder) service).getService();
            if (locationService != null) {
                updateUi();
                locationService.setOnStateListener(new LocationService.OnStateListener() {
                    @Override
                    public void onEnd() {
                        start.setImageResource(R.drawable.start_run);
                        allInfo.setVisibility(View.VISIBLE);
                        runInfo.setVisibility(View.GONE);
                    }

                    @Override
                    public void onStart() {
                        start.setImageResource(R.drawable.push_run);
                        allInfo.setVisibility(View.GONE);
                        runInfo.setVisibility(View.VISIBLE);
                        initRunInfo();
                    }

                    @Override
                    public void update(LocationItem locationItem, int time) {
                        updateRunInfo(locationItem, time);
                    }

                    @Override
                    public void updateTime(int time) {
                        Message msg = new Message();
                        msg.what = MESSAGE_UPDATE_TIME;
                        msg.obj = time;
                        handler.sendMessage(msg);
                    }
                });
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    private void updateUi() {
        if (locationService == null) {
            return;
        }
        switch (locationService.getState()) {
            case LocationService.STATE_NORMAL:
                start.setImageResource(R.drawable.start_run);
                start.setVisibility(View.VISIBLE);
                allInfo.setVisibility(View.VISIBLE);
                runInfo.setVisibility(View.GONE);
                findGps.setVisibility(View.GONE);
                pushControl.setVisibility(View.GONE);
                break;
            case LocationService.STATE_PUSH:
                start.setImageResource(R.drawable.push_run);
                start.setVisibility(View.GONE);
                allInfo.setVisibility(View.GONE);
                runInfo.setVisibility(View.VISIBLE);
                findGps.setVisibility(View.GONE);
                pushControl.setVisibility(View.VISIBLE);
                break;
            case LocationService.STATE_RUN_PREPARE:
                start.setImageResource(R.drawable.start_run);
                start.setVisibility(View.VISIBLE);
                allInfo.setVisibility(View.VISIBLE);
                runInfo.setVisibility(View.GONE);
                findGps.setVisibility(View.VISIBLE);
                pushControl.setVisibility(View.GONE);
                break;
            case LocationService.STATE_RUNNING:
                start.setImageResource(R.drawable.push_run);
                start.setVisibility(View.VISIBLE);
                allInfo.setVisibility(View.GONE);
                runInfo.setVisibility(View.VISIBLE);
                findGps.setVisibility(View.GONE);
                pushControl.setVisibility(View.GONE);
                break;
        }
    }

    private void initMap() {
        if (aMap == null) {
            aMap = mapView.getMap();
        }
        aMap.setLocationSource(this);// 设置定位监听
        aMap.getUiSettings().setMyLocationButtonEnabled(false);// 设置默认定位按钮是否显示
        aMap.setMyLocationEnabled(true);// 设置为true表示显示定位层并可触发定位，false表示隐藏定位层并不可触发定位，默认是false
        // 设置定位的类型为定位模式 ，可以由定位、跟随或地图根据面向方向旋转几种
        aMap.setMyLocationType(AMap.LOCATION_TYPE_LOCATE);

        CameraUpdate update = CameraUpdateFactory.zoomTo(17);
        aMap.moveCamera(update);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mapView.onSaveInstanceState(outState);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mapView.onResume();
        updateUi();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mapView.onPause();
    }

    @Override
    protected void onDestroy() {
        deactivate();
        mapView.onDestroy();
        if (locationService.getState() == LocationService.STATE_NORMAL) {
            locationService.stopSelf();
        }
        unbindService(serviceConnect);
        super.onDestroy();
    }

    @OnClick(R.id.start)
    public void start() {
        if (locationService != null) {
            locationService.prepareRun(this, aMap);
        } else {
            showToast("正在连接定位服务,请稍后重试");
        }
    }

    @OnClick(R.id.detail)
    public void detail() {
        openActivity(RunDetail.class);
    }

    @Override
    public void onLocationChanged(AMapLocation amapLocation) {
        if (myLocationListener != null && amapLocation != null) {
            myLocationListener.onLocationChanged(amapLocation);// 显示系统小蓝点
        }
    }

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == MESSAGE_UPDATE_TIME) {
                tvTime.setText(StringUtil.formatTime((Integer.valueOf(msg.obj.toString())) * 1000));
            }
        }
    };

    private void initRunInfo() {
        distance = 0; // 距离
        tvTime.setText("00:00:00");
        tvSpeed.setText("0");
        tvDistance.setText("0");
        tvCalories.setText("0");
    }

    private void updateRunInfo(LocationItem item, int time) {
        boolean isInitDistance;
        if (locationList.size() == 0) {
            isInitDistance = true;
            locationList = dbHelper.getCurrentRunLocationList();
        } else {
            isInitDistance = false;
            locationList.add(item);
            distance += item.distance;
        }
        if (locationList.size() < 2) {
            return;
        }

        PolylineOptions options = new PolylineOptions();
        for (int i = 0; i < locationList.size(); i++) {
            if (isInitDistance) {
                distance += locationList.get(i).distance;
            }
            options.add(new LatLng(locationList.get(i).lat, locationList.get(i).lon));
        }
        aMap.clear();

        polyline = aMap.addPolyline(options);
        LatLng startLatLng = new LatLng(locationList.get(0).lat, locationList.get(0).lon);
        LatLng endLatLng = new LatLng(locationList.get(locationList.size() - 1).lat, locationList.get(locationList.size() - 1).lon);
        LatLng center = new LatLng((startLatLng.latitude + endLatLng.latitude) / 2, (endLatLng.longitude + endLatLng.longitude) / 2);
        aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(center, 18));

        aMap.addMarker(new MarkerOptions()
                .position(startLatLng)
                .icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_start))));
        aMap.addMarker(new MarkerOptions()
                .position(endLatLng)
                .icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_end))));

        String speed = new DecimalFormat("0.00").format(distance / 1000 / ((double) time / 60 / 60));
        String distanceStr = new DecimalFormat("0.00").format(distance / 1000);
        String calories = MyUtil.getCalories(userInfo.getWeight(), distance) + "";
        tvSpeed.setText(speed);
        tvDistance.setText(distanceStr);
        tvCalories.setText(calories);

    }

    @Override
    public void activate(OnLocationChangedListener listener) {
        myLocationListener = listener;
        if (mAMapLocationManager == null) {
            mAMapLocationManager = LocationManagerProxy.getInstance(this);
            // 此方法为每隔固定时间会发起一次定位请求，为了减少电量消耗或网络流量消耗，
            // 注意设置合适的定位时间的间隔（最小间隔支持为2000ms），并且在合适时间调用removeUpdates()方法来取消定位请求
            // 在定位结束后，在合适的生命周期调用destroy()方法
            // 其中如果间隔时间为-1，则定位只定一次
            // 在单次定位情况下，定位无论成功与否，都无需调用removeUpdates()方法移除请求，定位sdk内部会移除
            mAMapLocationManager.requestLocationData(
                    LocationProviderProxy.AMapNetwork, 50 * 1000, 5, this);
            mAMapLocationManager.addGpsStatusListener(new GpsStatus.Listener() {
                @Override
                public void onGpsStatusChanged(int event) {
                    GpsStatus status = mAMapLocationManager.getGpsStatus(null); // 取当前状态
                    updateGpsStatus(event, status);
                }
            });
        }
    }

    private void updateGpsStatus(int event, GpsStatus status) {
        if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) {
            int maxSatellites = status.getMaxSatellites();
            Iterator<GpsSatellite> it = status.getSatellites().iterator();
            int count = 0;
            while (it.hasNext() && count <= maxSatellites) {
                GpsSatellite s = it.next();
                if (s.usedInFix()) { // 可以用来 gps 定位
                    count++;
                }
            }
            if (count < 3) {
                icGps.setImageResource(R.drawable.gps3);
            } else if (count < 7) {
                icGps.setImageResource(R.drawable.gps2);
            } else {
                icGps.setImageResource(R.drawable.gps1);
            }
        }
    }

    @Override
    public void deactivate() {
        myLocationListener = null;
        if (mAMapLocationManager != null) {
            mAMapLocationManager.removeUpdates(this);
            mAMapLocationManager.destroy();
        }
        mAMapLocationManager = null;
    }

    @Override
    public void onLocationChanged(Location location) {

    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }

    @Override
    public void onBackPressed() {
        if (findGps.getVisibility() != View.GONE) {
            findGps.setVisibility(View.GONE);
            locationService.setState(LocationService.STATE_NORMAL);
            return;
        } else if (locationService.getState() == LocationService.STATE_RUNNING) {
            new AlertDialog.Builder(this).setTitle("终止跑步并退出应用?")
                    .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            locationService.stopSelf();
                            finish();
                        }
                    })
                    .setNegativeButton("取消", null)
                    .show();
            return;
        }
        super.onBackPressed();
    }

    @OnClick(R.id.goon)
    public void goon() {
        pushControl.setVisibility(View.GONE);
        start.setVisibility(View.VISIBLE);
        locationService.setState(LocationService.STATE_RUNNING);
    }

    @OnClick(R.id.complete)
    public void complete() {
        pushControl.setVisibility(View.GONE);
        start.setVisibility(View.VISIBLE);
        locationService.completeRun(aMap);
        final LocationItem endItem = dbHelper.endRun(locationService.getStepsAll(), locationService.getTime());
        LocationItem startItem = locationService.getStartItem();
        if (startItem != null && endItem != null) {
            Net net = new Net(this, JsonApi.uploadSportData);
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            net.setParams("begin_time", format.format(new Date(startItem.time)));
            net.setParams("end_time", format.format(new Date(endItem.time)));
            net.setParams("duration", StringUtil.formatTime(endItem.duration));
            net.setParams("distance", new DecimalFormat("0.00").format(endItem.allDistance / 1000));
            net.setParams("speed", new DecimalFormat("0.00").format(endItem.speed));
            net.setParams("calorie", MyUtil.getCalories(userInfo.getWeight(), endItem.allDistance));
            net.setParams("begin_latitude", startItem.lat);
            net.setParams("begin_longitude", startItem.lon);
            net.setParams("end_latitude", endItem.lat);
            net.setParams("end_longitude", endItem.lon);
            net.setParams("run_step", endItem.step);
            net.sendPost(new NetUtil.OnJsonResultListener() {
                @Override
                public void onSuccess(String data) {
                    try {
                        JSONObject json = new JSONObject(data);
                        endItem.id = json.getString("id");
                        dbHelper.update(endItem);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onFail(int code, String data) {
                    showToast("上传跑步记录失败");
                }
            });
        }
    }
}
